package xw4g08.btc;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.ValueFactory;
import org.openrdf.query.Binding;
import org.openrdf.query.BindingSet;
import org.openrdf.query.MalformedQueryException;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.query.QueryLanguage;
import org.openrdf.query.TupleQuery;
import org.openrdf.query.TupleQueryResult;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.sail.SailRepository;
import org.openrdf.rio.RDFParseException;
import org.openrdf.sail.nativerdf.NativeStore;

import xw4g08.Configuration;
import xw4g08.Splitter;

public class SameAsCount {

	final static String owl_sameas = "http://www.w3.org/2002/07/owl#sameAs";
	static String inputDir = "C:\\Projects\\BTCSA";
	static String resultfile = "temp"+File.separator +"sacount.txt";
	final static String sasub = "SELECT (COUNT(?s) AS ?num) WHERE {?s <http://www.w3.org/2002/07/owl#sameAs> ?o.} GROUP BY ?s";
	final static String sapre = "SELECT ?s (COUNT(?s) AS ?num) WHERE {{?x ?s ?y. ?s <http://www.w3.org/2002/07/owl#sameAs> ?o.} UNION {?x ?s ?y. ?o <http://www.w3.org/2002/07/owl#sameAs> ?s.}} GROUP BY ?s";
	final static String saobj = "SELECT ?o (COUNT(?o) AS ?num) WHERE {?s <http://www.w3.org/2002/07/owl#sameAs> ?o.} GROUP BY ?o";
	static int total_num = 0;
	public static void main(String[] args) {
		File[] input = {new File("C:\\Projects\\BTCSA\\merged.trig")};
		Map<Value, Integer> val_num = SAPredicateCount(input);
		output(val_num,new File("temp"+File.separator +"pre_sacount.txt"));
		//output(statCal(resultfile),new File("temp" + File.separator +"sadistr.txt"));
		System.out.println(total_num);
		System.out.println("Finished!");
	}
	
	/**
	 * Get the number of co-references of each predicate
	 * @param inputs
	 * @return A map of each predicates to its number of co-ref
	 */
	static Map<Value, Integer> SAPredicateCount(File[] inputs) {
		Map<Value, Integer> val_num = new HashMap<Value, Integer>();
		
		File repDir = new File(Configuration.BASE_DIR, "repository").getAbsoluteFile();
		Repository rep = new SailRepository(new NativeStore(repDir));
		try {
			rep.initialize();
			RepositoryConnection con = rep.getConnection();
			System.out.println("Loading...");
			for(File input:inputs) {
				long start = System.nanoTime();
				con.add(input, null,Splitter.getFileType(input.getName()));
				long end = System.nanoTime();
				Long interval = end-start;
				System.out.println(input.getName() + " loaded in " + interval/1000000000 + " seconds.");
			}
				
			
			ValueFactory vf = con.getValueFactory();
			vf.createURI(owl_sameas);
			System.out.println("Counting predicates");
			TupleQuery qry = con.prepareTupleQuery(QueryLanguage.SPARQL, sapre);
			TupleQueryResult results = qry.evaluate();
			
			while(results.hasNext()) {
				BindingSet binding = results.next();
				Binding subbinding = binding.getBinding("s");
				if(subbinding == null) {
					continue;
				}
				Value sub = binding.getBinding("s").getValue();
				Value num = binding.getBinding("num").getValue();
				int count = Integer.parseInt(num.stringValue());
				val_num.put(sub, count);
				total_num += count;
			}
		} catch (RepositoryException e) {
			e.printStackTrace();
		} catch (RDFParseException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (MalformedQueryException e) {
			e.printStackTrace();
		} catch (QueryEvaluationException e) {
			e.printStackTrace();
		}
		
		return val_num ;
	}
	
	/**
	 * Get the number of co-references of each non-predicate
	 * @param inputs
	 * @return A map of each non-predicates to its number of co-ref
	 */
	static Map<Value, Integer> SAcount(File[] inputs) {
		Map<Value, Integer> val_num = new HashMap<Value, Integer>();
		File repDir = new File(Configuration.BASE_DIR, "repository").getAbsoluteFile();
		Repository rep = new SailRepository(new NativeStore(repDir));
		try {
			rep.initialize();
			RepositoryConnection con = rep.getConnection();
			System.out.println("Loading...");
			for(File input:inputs) {
				long start = System.nanoTime();
				con.add(input, null,Splitter.getFileType(input.getName()));
				long end = System.nanoTime();
				Long interval = end-start;
				System.out.println(input.getName() + " loaded in " + interval/1000000000 + " seconds.");
			}
				
			
			ValueFactory vf = con.getValueFactory();
			vf.createURI(owl_sameas);
			System.out.println("Counting subjects");
			TupleQuery qry = con.prepareTupleQuery(QueryLanguage.SPARQL, sasub);
			TupleQueryResult results = qry.evaluate();
			
			while(results.hasNext()) {
				BindingSet binding = results.next();
				Value sub = binding.getBinding("s").getValue();
				Value num = binding.getBinding("num").getValue();
				int count = Integer.parseInt(num.stringValue());
				val_num.put(sub, count);
				total_num += count;
			}
			
			System.out.println("Counting objects");
			qry = con.prepareTupleQuery(QueryLanguage.SPARQL, saobj);
			results = qry.evaluate();
			
			while(results.hasNext()) {
				BindingSet binding = results.next();
				Value obj = binding.getBinding("o").getValue();
				Value num = binding.getBinding("num").getValue();
				int count = Integer.parseInt(num.stringValue());
				
				int tem;
				if(val_num.get(obj) == null)
					tem = 0;
				else tem = val_num.get(obj);
				
				val_num.put(obj, tem + count);
			}
			
		} catch (RepositoryException e) {
			e.printStackTrace();
		} catch (RDFParseException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (MalformedQueryException e) {
			e.printStackTrace();
		} catch (QueryEvaluationException e) {
			e.printStackTrace();
		}
		
		/*Iterator<Entry<Value, Integer>> iter = val_num.entrySet().iterator();
		while(iter.hasNext())
			System.out.println(iter.next());*/
		
		System.out.println(total_num);
		return val_num;
	}
	
	static void output(Map val_num, File output) {
		try {
			FileOutputStream out = new FileOutputStream(output);
			PrintWriter writer = new PrintWriter(out);
			//writer.println("#"+total_num);
			Iterator keys = val_num.keySet().iterator();
			while(keys.hasNext()) {
				Object key = keys.next();
				String line = key.toString() + " " +val_num.get(key).toString();
				//byte[] bytes = line.getBytes();
				
				writer.println(line);
				
			}
			writer.close();
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Find out the distribution of co-references
	 * @param input
	 * @return A map of the number of co-ref to the number of URIs having that number of co-ref
	 */
	static Map<Integer,Integer> statCal(String input) {
		Map<Integer,Integer> distribution = new HashMap<Integer,Integer>();//count the number of occurrence of resources having specific number of SA statements
		try {
			BufferedReader reader = new BufferedReader(new FileReader(input));
			String line = reader.readLine().substring(1);
			Integer.parseInt(line);
			line = reader.readLine();
			while(line != null) {
				String[] pair = line.split(" ");
				int countofsa = Integer.parseInt(pair[1]);
				if(distribution.get(countofsa) == null) {
					distribution.put(countofsa, 0);
				}
				distribution.put(countofsa, distribution.get(countofsa)+1);
				line = reader.readLine();
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return distribution;
		
	}
}
